/* Copyright (c) 2010, mitsuhisa.net
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of the misuhisa.net nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef TREE_HPP_
#define TREE_HPP_

#include "Value.hpp"
#include "Context.hpp"

namespace nyu {

class String;
class Block;

namespace parser {

class Tree {
public:
    virtual ~Tree();

    virtual Value eval(Context& c, bool is_tail = false) = 0;

    virtual Value evalPut(Value v, Context& c, bool is_tail = false);
    virtual Value evalSet(Value v, Context& c, bool is_tail = false);
    virtual Value evalIAdd(Value v, Context& c, bool is_tail = false);
    virtual Value evalIncr(Context& c, bool is_tail = false);

    virtual bool evalBool(Context& c, bool is_tail = false);
};

class TreeList : public Tree {
public:
    TreeList(Tree* value, TreeList* next = 0);
    virtual ~TreeList();

    virtual Value eval(Context& c, bool is_tail = false);

    TreeList* reverse() {
        TreeList* l = this;
        TreeList* m = 0;
        TreeList* n = 0;

        while (l) {
            n = l->next_;
            l->next_ = m;
            m = l;
            l = n;
        }

        return m;
    }

    size_t length() const {
        size_t ret = 0;

        for (const TreeList* l = this; l; l = l->next_) {
            ++ret;
        }

        return ret;
    }

    Tree* value() {
        return value_;
    }

    TreeList* next() {
        return next_;
    }

private:
    Tree* value_;
    TreeList* next_;
};

class TreeUnit : public Tree {
public:
    TreeUnit(TreeList* stmts = 0);
    virtual ~TreeUnit();

    virtual Value eval(Context& c, bool is_tail = false);

private:
    TreeList* stmts_;
};

class TreeExpr1 : public Tree {
public:
    TreeExpr1(Tree* node);
    virtual ~TreeExpr1();

protected:
    Tree* node_;
};

#define NYU_DEFINE_EXPR1(NAME) \
class Tree##NAME : public TreeExpr1 { \
public: \
    Tree##NAME(Tree* node) : TreeExpr1(node) { \
    } \
 \
    virtual Value eval(Context& c, bool is_tail = false); \
}

NYU_DEFINE_EXPR1(Not);
NYU_DEFINE_EXPR1(Invert);
NYU_DEFINE_EXPR1(Pos);
NYU_DEFINE_EXPR1(Neg);
NYU_DEFINE_EXPR1(Incr);
NYU_DEFINE_EXPR1(Decr);
NYU_DEFINE_EXPR1(PostIncr);
NYU_DEFINE_EXPR1(PostDecr);

#undef NYU_DEFINE_EXPR1

class TreeExpr2 : public Tree {
public:
    TreeExpr2(Tree* lnode, Tree* rnode);
    virtual ~TreeExpr2();

protected:
    Tree* lnode_;
    Tree* rnode_;
};

#define NYU_DEFINE_EXPR2(NAME) \
class Tree##NAME : public TreeExpr2 { \
public: \
    Tree##NAME(Tree* lnode, Tree* rnode) : TreeExpr2(lnode, rnode) { \
    } \
 \
    virtual Value eval(Context& c, bool is_tail = false); \
}

NYU_DEFINE_EXPR2(LOr);
NYU_DEFINE_EXPR2(LXor);
NYU_DEFINE_EXPR2(LAnd);
NYU_DEFINE_EXPR2(Or);
NYU_DEFINE_EXPR2(Xor);
NYU_DEFINE_EXPR2(And);
NYU_DEFINE_EXPR2(LShift);
NYU_DEFINE_EXPR2(RShift);
NYU_DEFINE_EXPR2(Add);
NYU_DEFINE_EXPR2(Sub);
NYU_DEFINE_EXPR2(Mul);
NYU_DEFINE_EXPR2(Div);
NYU_DEFINE_EXPR2(Mod);
NYU_DEFINE_EXPR2(Cmp);

NYU_DEFINE_EXPR2(Put);
NYU_DEFINE_EXPR2(Set);
NYU_DEFINE_EXPR2(IAdd);
NYU_DEFINE_EXPR2(ISub);
NYU_DEFINE_EXPR2(IMul);
NYU_DEFINE_EXPR2(IDiv);
NYU_DEFINE_EXPR2(IMod);
NYU_DEFINE_EXPR2(ILShift);
NYU_DEFINE_EXPR2(IRShift);
NYU_DEFINE_EXPR2(IAnd);
NYU_DEFINE_EXPR2(IXor);
NYU_DEFINE_EXPR2(IOr);
NYU_DEFINE_EXPR2(ILAnd);
NYU_DEFINE_EXPR2(ILOr);

#undef NYU_DEFINE_EXPR2

class TreeExpr2Bool : public TreeExpr2 {
public:
    TreeExpr2Bool(Tree* lnode, Tree* rnode) : TreeExpr2(lnode, rnode) {
    }

    virtual Value eval(Context& c, bool is_tail = false);
};

#define NYU_DEFINE_EXPR2B(NAME) \
class Tree##NAME : public TreeExpr2Bool { \
public: \
    Tree##NAME(Tree* lnode, Tree* rnode) : TreeExpr2Bool(lnode, rnode) { \
    } \
 \
    virtual bool evalBool(Context& c, bool is_tail = false); \
}

NYU_DEFINE_EXPR2B(Eq);
NYU_DEFINE_EXPR2B(Ne);
NYU_DEFINE_EXPR2B(Lt);
NYU_DEFINE_EXPR2B(Le);
NYU_DEFINE_EXPR2B(Gt);
NYU_DEFINE_EXPR2B(Ge);
NYU_DEFINE_EXPR2B(OwnProto);
NYU_DEFINE_EXPR2B(OwnMember);

#undef NYU_DEFINE_EXPR2B

class TreeCond : public Tree {
public:
    TreeCond(Tree* cond, Tree* tnode, Tree* fnode);
    virtual ~TreeCond();

    virtual Value eval(Context& c, bool is_tail = false);

private:
    Tree* cond_;
    Tree* tnode_;
    Tree* fnode_;
};

class TreeCall : public Tree {
public:
    TreeCall(Tree* expr, TreeList* args = 0);
    virtual ~TreeCall();

    virtual Value eval(Context& c, bool is_tail = false);

private:
    Value updateScope(Context& c, const Value& val);

    Tree* expr_;
    TreeList* args_;
};

class TreeSymbol : public Tree {
public:
    TreeSymbol(char* symbol);
    virtual ~TreeSymbol();

    virtual Value eval(Context& c, bool is_tail = false);

    virtual Value evalPut(Value v, Context& c, bool is_tail = false);
    virtual Value evalSet(Value v, Context& c, bool is_tail = false);
    virtual Value evalIAdd(Value v, Context& c, bool is_tail = false);
    virtual Value evalIncr(Context& c, bool is_tail = false);

private:
    String* symbol_;
    unsigned int symidx_;
};

class TreeInt : public Tree {
public:
    TreeInt(int_type value);

    virtual Value eval(Context& c, bool is_tail = false);

private:
    int_type value_;
};

class TreeFloat : public Tree {
public:
    TreeFloat(float_type value);

    virtual Value eval(Context& c, bool is_tail = false);

private:
    float_type value_;
};

class TreeStr : public Tree {
public:
    TreeStr(char* value);
    virtual ~TreeStr();

    virtual Value eval(Context& c, bool is_tail = false);

private:
    String* value_;
};

class TreeBlock : public Tree {
public:
    TreeBlock(TreeList* stmts);
    virtual ~TreeBlock();

    virtual Value eval(Context& c, bool is_tail = false);

private:
    Block* block_;
};

class TreeObject : public Tree {
public:
    TreeObject(TreeList* slots = 0);
    virtual ~TreeObject();

    virtual Value eval(Context& c, bool is_tail = false);

private:
    TreeList* slots_;
};

class TreeObjectSlot : public Tree {
public:
    TreeObjectSlot(char* name, Tree* value);
    virtual ~TreeObjectSlot();

    virtual Value eval(Context& c, bool is_tail = false);

    String* name() {
        return name_;
    }

    Tree* value() {
        return value_;
    }

private:
    String* name_;
    Tree* value_;
};

class TreeArray : public Tree {
public:
    TreeArray(TreeList* elms);
    virtual ~TreeArray();

    virtual Value eval(Context& c, bool is_tail = false);

private:
    TreeList* elms_;
    size_t nelms_;
};

class TreeRange : public Tree {
public:
    TreeRange(bool is_in, Tree* start, Tree* end, Tree* step = 0);
    virtual ~TreeRange();

    virtual Value eval(Context& c, bool is_tail = false);

private:
    bool is_in_;
    Tree* start_;
    Tree* end_;
    Tree* step_;
};

class TreeSlotAccess : public Tree {
public:
    TreeSlotAccess(Tree* expr, char* name);
    virtual ~TreeSlotAccess();

    virtual Value eval(Context& c, bool is_tail = false);

    virtual Value evalPut(Value v, Context& c, bool is_tail = false);
    virtual Value evalIAdd(Value v, Context& c, bool is_tail = false);

private:
    Tree* expr_;
    String* name_;
};

class TreeItemAccess : public Tree {
public:
    TreeItemAccess(Tree* expr, Tree* idx);
    virtual ~TreeItemAccess();

    virtual Value eval(Context& c, bool is_tail = false);

private:
    Tree* expr_;
    Tree* idx_;
};

class TreeArgref : public Tree {
public:
    TreeArgref(int index);

    virtual Value eval(Context& c, bool is_tail = false);

private:
    int index_;
};

class TreeArglen : public Tree {
public:
    TreeArglen();

    virtual Value eval(Context& c, bool is_tail = false);
};

class TreeCurblk : public Tree {
public:
    TreeCurblk();

    virtual Value eval(Context& c, bool is_tail = false);
};

}

}

#endif /* TREE_HPP_ */
